介绍
建造者模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
Builder 模式是一步一步创建一个复杂对象的创建型模式,它允许用户在不知道内部构建细节的情况下,可以更精细地控制对象的构造流程。该模式是为了将构建复杂对象的过程和它的部件解耦,使得构建过程和部件的表示隔离开来。
因为一个负责对象有大量组成部分,如汽车有车轮、方向盘、发动机、车盘,还有各种小零件,如何将这些部件装配成一辆汽车,这个装配过程很漫长,也很复杂,对于这种情况,为了在构建过程中对外部隐藏实现细节,就可以使用 Builder 模式将部件和组装过程分离,使得构建过程和部件都可以自由扩展,两者之间的耦合也降到最低。
使用场景
- 相同的方法,不同的执行顺序,产生不同的事件结果时。
- 多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时。
- 产品类非常复杂,或者产品类中的调用顺序不同产生了不同的作用,这个时候使用建造者模式非常合适。
- 当初始化一个对象特别复杂,如参数多,且很多参数都具有默认值时。
UML 类图
从上图可以看到,经典 Buider 模式中有四个角色:
- Product 产品类 —— 产品的抽象类;
- Builder —— 抽象 Builder 类,规范产品的组建,一般是由子类实现具体的组建过程;
- ConcreteBuilder —— 具体的 Builder 类;
- Director —— 统一组装过程。
示例
计算机的组装过程较为复杂,并且组装顺序是不固定的,为了易于理解,我们把计算机组装的过程简化为构建主机、设置操作系统、设置显示器 3 个部分,然后通过 Director 和具体的 Builder 来构建计算机对象。请看下面示例。
输出结果:
Computer Info : Computer [mBoard=英特尔主板, mDisplay=Retina 显示器, mOS=Mac OS X 10.10]
上述示例中,通过具体的 MacbookBuilder 来构建 Macbook 对象,而 Director 封装了构建复杂产品对象的过程,对外隐藏构建细节。Builder 与 Director 一起将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的对象。
值得注意的是,在现实开发过程当中,Director 角色经常会被省略。而直接使用一个 Builder 来进行对象的组装,这个 Builder 通常为链式调用,它的关键点是每个 setter 方法都返回自身,也就是 return this,这样就使得 setter 方法可以链式调用,代码大致如下。
通过这种形式不仅去除了 Director 角色,整个结构也更加简单,也能对 Product 对象的组装过程有更精细的控制。
ANDROID 源码中的 Builder 模式
在 ANDROID 源码中,最常用到的 Builder 模式就是 AlertDialog.Builder,使用该 Builder 来构建复杂的 AlertDialog 对象。在开发过程中,我们经常用到 AlertDialog,具体示例如下。
显示结果如下图所示。
从类名就可以看出这就是一个 Builder 模式,通过 Builder 对象来组装 Dialog 的各个部分,如 title、buttons、message 等,将 Dialog 的构造和表示进行分离。下面看看 AlertDialog 的相关源码。
上述代码中,Builder 类可以设置 AlertDialog 中的 title、message、button 等参数,这些参数都存储在类型为 AlertController.AlertParams 的成员变量 P 中,AlertController.AlertParams 中包含了与 AlertDialog 视图中对应的成员变量。在调用 Builder 类的 create 函数时会创建 AlertDialog,并且将 Builder 成员变量 P 中保存的参数应用到 AlertDialog 的 mAlert 对象中,即 P.apply(dialog.mAlert) 代码段。我们再看看 apply 函数的实现。
在 apply 函数中,只是将 AlertParams 参数设置到 AlertController 中,例如,将标题设置到 Dialog 对应的标题视图中,将 Message 设置到内容视图中等。当我们获取到 AlertDialog 对象后,通过 show 函数就可以显示这个对话框。而 show 函数最终调用的是 Dialog 类的 show 函数。
在 show 函数中主要做了如下几个事情:
- 通过 dispatchOnCreate 函数来调用 AlertDialog 的 onCreate 函数;
- 然后调用 AlertDialog 的 onStart 函数;
- 最后将 Dialog 的 DecorView 添加到 WindowManager 中。
这里的 AlertDialog.Builder 同时扮演了上文中提到的 Builder、ConcreteBuilder、Director 的角色,简化了 Builder 模式的设计。当模块比较稳定,不存在一些变化时,可以在经典模式实现的基础上做出一些精简,而不是照搬 GOF 上的经典实现,更不要生搬硬套,使程序失去架构之美。
Builder 模式实战
配置 ImageLoader 的参数:缓存、图片加载中显示的图片、加载失败后显示的图片、图片加载策略、线程数等。
把配置的代码基本上都封装到了 ImageLoaderConfig 和 Builder 对象中。其代码如下:
通过将 ImageLoaderConfig 的构造函数、字段私有化,使得外部不能访问内部属性,用户唯一能够设置属性的地方就是通过 Builder 对象了,也就是说用户只能通过 Builder 对象构造 ImageLoaderConfig 对象,这就是构建和表示相分离。
用户的使用代码如下所示。